#pragma once
#include<iostream>
#include<cstdio>
#include<string>
#include<sys/shm.h>
#include<sys/shm.h>
#include <unistd.h>

const std::string path=".";
const int gsize=4096;
int gproj_id = 0x66;

class SharedMemory
{
private:
    bool CreateHelper(int flags)
    {
        _key=ftok(path.c_str(),gproj_id);
        if(_key<0)
        {
            perror("ftok");
            return false;
        }
        std::cout<<"键值创建成功："<<_key<<std::endl;

        _shmid=shmget(_key,_size,flags);
        if(_shmid<0)
        {
            perror("shmget");
            return false;
        }
        std::cout<<"共享内存创建成功:"<<_shmid<<std::endl;
        return true;
    }
public:
    SharedMemory(int size=gsize)
        :_size(size)
        ,_key(0)
        ,_shmid(-1)
        ,_start_address(nullptr)
        ,_datastart(nullptr)
        ,_windex(0)
        ,_rindex(0)
        ,_num(nullptr)
    {}
    
    bool Create()
    {
        return  CreateHelper(IPC_CREAT | IPC_EXCL | 0666);
    }

    bool Get()
    {
        return CreateHelper(IPC_CREAT);
    }

    void SetZero()
    {
        *_num=0;
    }

    bool Attach()
    {
        _start_address=shmat(_shmid,nullptr,0);
        if((long long)_start_address==-1)
        {   
            perror("shmat");
            return false;
        }
        std::cout << "将指定的共享内存挂接到自己进程的地址空间:" << std::endl;

        printf("_start_addr : %p\n", _start_address);
        _num=(int*)_start_address;
        _datastart=(char*)_start_address+sizeof(int);
        return true;
    }

    bool Detach()
    {
        int n = shmdt(_start_address);
        if (n < 0)
        {
            perror("shmdt");
            return false;
        }
        std::cout << "将指定的共享内存从进程的地址空间移除" << std::endl;
        return true;
    }

    void AddChar(char ch)
    {
        if(*_num == _size)
            return;
        ((char*)_datastart)[_windex++] = ch;
        ((char*)_datastart)[_windex] = '\0';

        // std::cout << "debug: " << _windex << ", " << ch << std::endl;
        _windex %= _size;
        (*_num)++;
    }

    void PopChar(char *ch)
    {
        if(*_num == 0)
            return;
        *ch = ((char*)_datastart)[_rindex++];
        _rindex %= _size;
        (*_num)--;
        printf("%s\n", _datastart);
    }

    bool Remove()
    {
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        if(n < 0)
        {
            perror("shmctl");
            return false;
        }
        std::cout << "删除shm成功" << std::endl;
        return true;
    }

    ~SharedMemory() {}
private:
    key_t _key;
    int _size;
    int _shmid;
    void* _start_address;
    char* _datastart;
    int* _num;
    int _windex;
    int _rindex;
};